
using System;
using System.Collections.Generic;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;

namespace ScrewTurn.Wiki {

	/// <summary>
	/// Contains information about Page Redirections.
	/// </summary>
	public class Redirections {

		private static Redirections instance;

		/// <summary>
		/// Gets or sets the singleton instance of the <b>Redirections</b> object.
		/// </summary>
		public static Redirections Instance {
			get {
				if(instance == null) throw new InvalidOperationException("Redirections.Instance is null");
				return instance;
			}
			set { instance = value; }
		}

		private Dictionary<PageInfo, PageInfo> redirs;

		/// <summary>
		/// Initializes a new instance of the <b>Redirections</b> class.
		/// </summary>
		public Redirections() {
			redirs = new Dictionary<PageInfo, PageInfo>();
		}

		/// <summary>
		/// Adds a new Redirection.
		/// </summary>
		/// <param name="source">The source Page.</param>
		/// <param name="destination">The destination Page.</param>
		/// <returns>True if the Redirection is added, false otherwise.</returns>
		/// <remarks>The method prevents circular and multi-level redirection.</remarks>
		public bool AddRedirection(PageInfo source, PageInfo destination) {
			// Check whether destination already redirects
			PageInfo tmp = null;
			if(redirs.TryGetValue(destination, out tmp)) return false;

			redirs[source] = destination;
			return true;
		}

		/// <summary>
		/// Gets the destination Page.
		/// </summary>
		/// <param name="page">The source Page.</param>
		/// <returns>The destination Page, or null.</returns>
		public PageInfo GetDestination(PageInfo page) {
			PageInfo dest = null;
			if(!redirs.TryGetValue(page, out dest)) dest = null;
			return dest;
		}

		/// <summary>
		/// Removes any occurrence of a Page from the redirection table, both on sources and destinations.
		/// </summary>
		/// <param name="page">The Page to wipe-out.</param>
		/// <remarks>This method is useful when removing a Page.</remarks>
		public void WipePageOut(PageInfo page) {
			// Remove all page -> <something> redirections
			redirs.Remove(page);
			// Remove all <something> -> page redirections
			PageInfo[] keys = new PageInfo[redirs.Count];
			redirs.Keys.CopyTo(keys, 0);
			for(int i = 0; i < keys.Length; i++) {
				if(redirs[keys[i]] == page) redirs.Remove(keys[i]);
			}
		}

		/*
		/// <summary>
		/// Replaces any occurrence of a Page from the redirection table, both on sources and destinations.
		/// </summary>
		/// <param name="original">The Page to replace.</param>
		/// <param name="actual">The new Page.</param>
		/// <remarks>This method is useful when renaming a Page.</remarks>
		public void ReplacePage(PageInfo original, PageInfo actual) {
			// Fix all original -> <something> redirections
			PageInfo tmp = null;
			if(redirs.TryGetValue(original, out tmp)) {
				redirs.Remove(original);
				redirs.Add(actual, tmp);
			}
			// Fix all <something> -> original redirections
			PageInfo[] keys = new PageInfo[redirs.Count];
			redirs.Keys.CopyTo(keys, 0);
			for(int i = 0; i < keys.Length; i++) {
				if(redirs[keys[i]] == original) {
					redirs[keys[i]] = actual;
				}
			}
		}
		*/

		/// <summary>
		/// Clears the Redirection table.
		/// </summary>
		public void Clear() {
			redirs.Clear();
		}

	}

}
